/*************************************************
* Title：TinyToolKit
* Author：Opportunity 
* Discribe：获取多阶贝塞尔曲线的路径点
* CreateTime：2020-04-05 21:43:38
* Version：1.0
* Modify Recoder：
*************************************************/
using System.Collections.Generic;
using UnityEngine;

namespace TinyToolKit
{
    public static partial class TinyUtility
    {
        public static class Bezier
        {
            /// <summary>
            /// 一阶贝塞尔曲线
            /// </summary>
            public static Vector3 CalculateBezier(Vector3 p0, Vector3 p1, float t) 
            {
                return (1 - t) * p0 + t * p1;
            }

            /// <summary>
            /// 二阶贝塞尔曲线
            /// </summary>
            public static Vector3 CalculateBezier(Vector3 p0, Vector3 p1, Vector3 p2, float t)
            {
                Vector3 p0p1 = (1 - t) * p0 + t * p1;
                Vector3 p1p2 = (1 - t) * p1 + t * p2;
                Vector3 result = (1 - t) * p0p1 + t * p1p2;
                return result;
            }

            /// <summary>
            /// 三阶贝塞尔曲线
            /// </summary>
            public static Vector3 CalculateBezier(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
            {
                Vector3 result;
                Vector3 p0p1 = (1 - t) * p0 + t * p1;
                Vector3 p1p2 = (1 - t) * p1 + t * p2;
                Vector3 p2p3 = (1 - t) * p2 + t * p3;
                Vector3 p0p1p2 = (1 - t) * p0p1 + t * p1p2;
                Vector3 p1p2p3 = (1 - t) * p1p2 + t * p2p3;
                result = (1 - t) * p0p1p2 + t * p1p2p3;
                return result;
            }

            /// <summary>
            /// 多阶贝塞尔曲线，使用递归实现
            /// </summary>
            public static Vector3 CalculateBezier(List<Vector3> p, float t)
            {
                //如果当前计算的点少于两个，则结束递归计算
                if (p.Count < 2) return p[0];

                List<Vector3> newp = new List<Vector3>();
                for (int i = 0; i < p.Count - 1; i++)
                {
                    Vector3 p0p1 = (1 - t) * p[i] + t * p[i + 1];
                    newp.Add(p0p1);
                }
                return CalculateBezier(newp,t); 
            }

            /// <summary>
            /// 获取贝塞尔曲线点的路径
            /// </summary>
            /// <param name="startPoint">起始点</param>
            /// <param name="controlPoint">控制点</param>
            /// <param name="endPoint">目标点</param>
            /// <param name="segmentNum">采样点的数量</param>  
            /// <returns>存储贝塞尔曲线点的数组</returns> 
            public static Vector3[] GetBeizerPath(int segmentNum,params Vector3[] points) 
            {
                Vector3[] path = new Vector3[segmentNum];
                for (int i = 0; i < segmentNum; i++)
                {
                    float t = i / (float)(segmentNum - 1); 
                    Vector3 pointPos = GetBeizerPos(points, t);
                    path[i] = pointPos;
                }
                return path;
            }

            private static Vector3 GetBeizerPos(Vector3[] points,float t)
            {
                if (points.Length < 2) return points[0];

                int pointCount = points.Length;
                switch (pointCount)
                {
                    case 2:
                        return CalculateBezier(points[0], points[1], t);
                    case 3:
                        return CalculateBezier(points[0], points[1], points[2], t);
                    case 4:
                        return CalculateBezier(points[0], points[1], points[2], points[3], t);
                    default:
                        List<Vector3> p = new List<Vector3>(points);
                        return CalculateBezier(p, t);
                }
            }
        }
    }
}
